package net.butfly.bus.client;

import java.lang.reflect.Proxy;

import net.butfly.bus.Request;
import net.butfly.bus.Response;
import net.butfly.bus.context.Constants;
import net.butfly.bus.context.Constants.InternalTX;
import net.butfly.bus.exception.BusRuntimeException;

public class Client {
	private ClientInvoker invoker;

	public Client() {
		this.invoker = new ClientInvoker();
	}

	public <T> T invoke(InternalTX tx, Object... args) {
		return this.invoke(new TXRequest(tx), args);
	}

	public <T> T invoke(String tx, Object... args) {
		return this.invoke(new TXRequest(tx), args);
	}

	@SuppressWarnings("unchecked")
	public <T> T invoke(TXRequest tx, Object... args) {
		if (null == tx)
			throw new BusRuntimeException(Constants.UserError.TX_NOT_EXIST,
					"can't find tx annotation on invoked method.");

		Request request = new Request();
		request.setTx(tx.getTx());
		request.setVersion(tx.getVersion());
		request.setArgs(args != null ? args : new Object[0]);

		Response response = this.invoker.invoke(request);
		if (response.hasError()) {
			BusRuntimeException ee;
			String em = response.getErrorMessage();
			if (em != null) {
				if (em.indexOf(":") != -1) {
					em = em.substring(em.indexOf(":") + 1);
				}
				ee = new BusRuntimeException(response.getErrorCode(), em);
			} else {
				ee = new BusRuntimeException(response.getErrorCode());
			}
			if (response.getErrorStack() != null) {
				ee.setCause(new Throwable(response.getErrorStack()));
			}
			throw ee;
		}
		return (T) response.getResult();
	}

	@SuppressWarnings("unchecked")
	public <T> T newProxyInstance(Class<T> c) {
		return (T) Proxy.newProxyInstance(c.getClassLoader(), new Class<?>[] { c }, new ClientProxy(invoker));
	}
}
